﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using Microsoft.Practices.Composite.Events;
using Microsoft.Practices.Composite.Presentation.Commands;
using StockholmsStad.Windows.UI.Infrastructure.Properties;
using StockholmsStad.Windows.UI.Modules.Maintenance.BusinessEntities;

namespace StockholmsStad.Windows.UI.Modules.Maintenance.Models
{
    public class GenerateTimePresentationModel : INotifyPropertyChanged, IDataErrorInfo
    {
        private readonly IDictionary<string, string> errors = new Dictionary<string, string>();

        public event EventHandler<DataEventArgs<GenerateTimePresentationModel>> Generated;
        public event EventHandler<DataEventArgs<GenerateTimePresentationModel>> Saved;
        public event EventHandler<DataEventArgs<GenerateTimePresentationModel>> Cancelled;

        public DelegateCommand<object> GenerateCommand { get; private set; }
        public DelegateCommand<object> SaveCommand { get; private set; }
        public DelegateCommand<object> CancelCommand { get; private set; }

        #region Properties

        public string HeaderInfo
        {
            get { return HeaderNames.Scheduling; }
        }

        private DateTime? startDate;
        public DateTime? StartDate
        {
            get
            {
                return startDate;
            }
            set
            {
                if (!value.Equals(startDate))
                {
                    startDate = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("StartDate"));
                }
            }
        }

        private DateTime? endDate;
        public DateTime? EndDate
        {
            get
            {
                return endDate;
            }
            set
            {
                if (!value.Equals(endDate))
                {
                    endDate = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("EndDate"));
                }
            }
        }

        private string startTime;
        public string StartTime
        {
            get
            {
                return startTime;
            }
            set
            {
                if (!value.Equals(startTime))
                {
                    startTime = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("StartTime"));
                }
            }
        }

        private string endTime;
        public string EndTime
        {
            get
            {
                return endTime;
            }
            set
            {
                if (!value.Equals(endTime))
                {
                    endTime = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("EndTime"));
                }
            }
        }

        private int interval;
        public int Interval
        {
            get
            {
                return interval;
            }
            set
            {
                if (!value.Equals(interval))
                {
                    interval = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("Interval"));
                }
            }
        }

        private bool includeAnotherDay;
        public bool IncludeAnotherDay
        {
            get
            {
                return includeAnotherDay;
            }
            set
            {
                if (!value.Equals(includeAnotherDay))
                {
                    includeAnotherDay = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("IncludeAnotherDay"));
                }
            }
        }

        private ScheduledMonths scheduledMonths;
        public ScheduledMonths ScheduledMonths
        {
            get
            {
                return scheduledMonths;
            }
            set
            {
                if (!value.Equals(scheduledMonths))
                {
                    scheduledMonths = value;
                    PropertyChanged(this, new PropertyChangedEventArgs("ScheduledMonths"));
                }
            }
        }

        #endregion

        #region ErrorHandling and Validation

        private void ClearError(string columnName)
        {
            if (errors.ContainsKey(columnName))
                errors.Remove(columnName);
        }

        private void Validate()
        {
            if (!string.IsNullOrEmpty(StartTime))
            {
                DateTime res;
                if (!DateTime.TryParse(StartTime, out res))
                    this["StartTime"] = Resources.InvalidStartTime;
                else
                    ClearError("StartTime");
            }
            else
            {
                ClearError("StartTime");
            }

            if (!string.IsNullOrEmpty(EndTime))
            {
                DateTime res;
                if (!DateTime.TryParse(EndTime, out res))
                    this["EndTime"] = Resources.InvalidEndTime;
                else
                    ClearError("EndTime");
            }
            else
            {
                ClearError("EndTime");
            }

        }

        #endregion

        #region Contructor
        public GenerateTimePresentationModel()
        {
            GenerateCommand = new DelegateCommand<object>(Generate, CanGenerate);
            SaveCommand = new DelegateCommand<object>(Save);
            CancelCommand = new DelegateCommand<object>(Cancel);

            PropertyChanged += OnPropertyChangedEvent;
            Validate();
        }
        #endregion

        private void ClearFields()
        {
            StartDate = null;
            EndDate = null;
            StartTime = string.Empty;
            EndTime = string.Empty;
            Interval = 0;
            IncludeAnotherDay = false;
        }

        private void OnPropertyChangedEvent(object sender, PropertyChangedEventArgs e)
        {
            Validate();

            GenerateCommand.RaiseCanExecuteChanged();
        }

        private bool CanGenerate(object obj)
        {
            bool canSave = false;

            if(IncludeAnotherDay && StartDate.HasValue)
            {
                canSave = true;
            }
            else
            {
                if(StartDate.HasValue && EndDate.HasValue && StartDate.Value.CompareTo(EndDate.Value) < 0)
                    canSave = true;
            }

            return errors.Count == 0 && canSave;
        }

        private void Generate(object obj)
        {
            if (CanGenerate(obj))
                OnGenerated(new DataEventArgs<GenerateTimePresentationModel>(this));
        }

        private void Save(object obj)
        {
            OnSaved(new DataEventArgs<GenerateTimePresentationModel>(this));
        }

        private void Cancel(object obj)
        {
            OnCancelled(new DataEventArgs<GenerateTimePresentationModel>(this));
        }

        private void OnGenerated(DataEventArgs<GenerateTimePresentationModel> e)
        {
            var generatedHandler = Generated;

            if (generatedHandler != null)
                generatedHandler(this, e);

            ClearFields();
        }

        private void OnSaved(DataEventArgs<GenerateTimePresentationModel> e)
        {
            var savedHandler = Saved;

            if (savedHandler != null)
                savedHandler(this, e);
        }

        private void OnCancelled(DataEventArgs<GenerateTimePresentationModel> e)
        {
            var cancelledHandler = Cancelled;

            if (cancelledHandler != null)
                cancelledHandler(this, e);
        }

        #region INotifyPropertyChanged Members

        public event PropertyChangedEventHandler PropertyChanged;

        #endregion

        #region IDataErrorInfo Members

        public string Error
        {
            get
            {
                // Inte implementerad, då vi inte använder denna, vi visar fel på varje kontroll istället.
                throw new NotImplementedException();
            }
        }

        public string this[string columnName]
        {
            get
            {
                if (errors.ContainsKey(columnName))
                    return errors[columnName];

                return null;
            }
            set
            {
                errors[columnName] = value;
            }
        }

        #endregion
    }
}